/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.util;

import com.aduib.boot.common.exception.CommonException;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;

/**
 * @description: URLUtils
 * @author: zzh
 * @date: 2021/10/28 16:38
 */
public class URLUtils {
  /**
   * 转URL为URI
   *
   * @param url URL
   * @return URI
   * @throws CommonException 包装URISyntaxException
   */
  public static URI toURI(URL url) throws CommonException {
    return toURI(url, false);
  }

  /**
   * 转URL为URI
   *
   * @param url URL
   * @param isEncode 是否编码参数中的特殊字符（默认UTF-8编码）
   * @return URI
   * @throws CommonException 包装URISyntaxException
   */
  public static URI toURI(URL url, boolean isEncode) throws CommonException {
    if (null == url) {
      return null;
    }

    return toURI(url.toString(), isEncode);
  }

  /**
   * 转字符串为URI
   *
   * @param location 字符串路径
   * @return URI
   * @throws CommonException 包装URISyntaxException
   */
  public static URI toURI(String location) throws CommonException {
    return toURI(location, false);
  }

  /**
   * 转字符串为URI
   *
   * @param location 字符串路径
   * @param isEncode 是否编码参数中的特殊字符（默认UTF-8编码）
   * @return URI
   * @throws CommonException 包装URISyntaxException
   */
  public static URI toURI(String location, boolean isEncode) throws CommonException {
    if (isEncode) {
      location = encode(location);
    }
    try {
      return new URI(StrUtils.trim(location));
    } catch (URISyntaxException e) {
      throw new CommonException(e);
    }
  }

  /**
   * 编码URL，默认使用UTF-8编码<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。
   *
   * @param url URL
   * @return 编码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String encodeAll(String url) {
    return encodeAll(url, CharsetUtils.CHARSET_UTF_8);
  }

  /**
   * 编码URL<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。
   *
   * @param url URL
   * @param charset 编码，为null表示不编码
   * @return 编码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String encodeAll(String url, Charset charset) throws CommonException {
    if (null == charset || StrUtils.isEmpty(url)) {
      return url;
    }

    return URLEncoder.ALL.encode(url, charset);
  }

  /**
   * 编码URL，默认使用UTF-8编码<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。<br>
   * 此方法用于URL自动编码，类似于浏览器中键入地址自动编码，对于像类似于“/”的字符不再编码
   *
   * @param url URL
   * @return 编码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String encode(String url) throws CommonException {
    return encode(url, CharsetUtils.CHARSET_UTF_8);
  }

  /**
   * 编码URL，默认使用UTF-8编码<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。<br>
   * 此方法用于POST请求中的请求体自动编码，转义大部分特殊字符
   *
   * @param url URL
   * @return 编码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String encodeQuery(String url) throws CommonException {
    return encodeQuery(url, CharsetUtils.CHARSET_UTF_8);
  }

  /**
   * 编码字符为 application/x-www-form-urlencoded<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。<br>
   * 此方法用于URL自动编码，类似于浏览器中键入地址自动编码，对于像类似于“/”的字符不再编码
   *
   * @param url 被编码内容
   * @param charset 编码
   * @return 编码后的字符
   */
  public static String encode(String url, Charset charset) {
    if (StrUtils.isEmpty(url)) {
      return url;
    }
    if (null == charset) {
      charset = CharsetUtils.defaultCharset();
    }
    return URLEncoder.DEFAULT.encode(url, charset);
  }

  /**
   * 编码字符为URL中查询语句<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。<br>
   * 此方法用于POST请求中的请求体自动编码，转义大部分特殊字符
   *
   * @param url 被编码内容
   * @param charset 编码
   * @return 编码后的字符
   */
  public static String encodeQuery(String url, Charset charset) {
    if (StrUtils.isEmpty(url)) {
      return url;
    }
    if (null == charset) {
      charset = CharsetUtils.defaultCharset();
    }
    return URLEncoder.QUERY.encode(url, charset);
  }

  /**
   * 编码URL字符为 application/x-www-form-urlencoded<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。<br>
   * 此方法用于URL自动编码，类似于浏览器中键入地址自动编码，对于像类似于“/”的字符不再编码
   *
   * @param url URL
   * @param charset 编码
   * @return 编码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String encode(String url, String charset) throws CommonException {
    if (StrUtils.isEmpty(url)) {
      return url;
    }
    return encode(
        url,
        StrUtils.isBlank(charset) ? CharsetUtils.defaultCharset() : CharsetUtils.charset(charset));
  }

  /**
   * 编码URL<br>
   * 将需要转换的内容（ASCII码形式之外的内容），用十六进制表示法转换出来，并在之前加上%开头。<br>
   * 此方法用于POST请求中的请求体自动编码，转义大部分特殊字符
   *
   * @param url URL
   * @param charset 编码
   * @return 编码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String encodeQuery(String url, String charset) throws CommonException {
    return encodeQuery(
        url,
        StrUtils.isBlank(charset) ? CharsetUtils.defaultCharset() : CharsetUtils.charset(charset));
  }

  /**
   * 解码URL<br>
   * 将%开头的16进制表示的内容解码。
   *
   * @param url URL
   * @return 解码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String decode(String url) throws CommonException {
    return decode(url, CharsetUtils.UTF_8);
  }

  /**
   * 解码application/x-www-form-urlencoded字符<br>
   * 将%开头的16进制表示的内容解码。
   *
   * @param content 被解码内容
   * @param charset 编码，null表示不解码
   * @return 编码后的字符
   */
  public static String decode(String content, Charset charset) {
    if (null == charset) {
      return content;
    }
    return URLDecoder.decode(content, charset);
  }

  /**
   * 解码application/x-www-form-urlencoded字符<br>
   * 将%开头的16进制表示的内容解码。
   *
   * @param content URL
   * @param charset 编码
   * @return 解码后的URL
   * @throws CommonException UnsupportedEncodingException
   */
  public static String decode(String content, String charset) throws CommonException {
    return decode(content, CharsetUtils.charset(charset));
  }

  /**
   * 获得path部分<br>
   *
   * @param uriStr URI路径
   * @return path
   * @throws CommonException 包装URISyntaxException
   */
  public static String getPath(String uriStr) {
    return toURI(uriStr).getPath();
  }

  /**
   * 从URL对象中获取不被编码的路径Path<br>
   * 对于本地路径，URL对象的getPath方法对于包含中文或空格时会被编码，导致本读路径读取错误。<br>
   * 此方法将URL转为URI后获取路径用于解决路径被编码的问题
   *
   * @param url {@link URL}
   * @return 路径
   */
  public static String getDecodedPath(URL url) {
    if (null == url) {
      return null;
    }

    String path = null;
    try {
      // URL对象的getPath方法对于包含中文或空格的问题
      path = toURI(url).getPath();
    } catch (CommonException e) {
      // ignore
    }
    return (null != path) ? path : url.getPath();
  }
}
